package com.mpgame.common.manager;

import com.mpgame.common.proto.CmdId;
import com.mpgame.common.proto.ErrorCode;
import com.mpgame.common.proto.GamePacket;
import com.mpgame.common.utils.Log;

import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

import io.netty.channel.Channel;

public class HeartbeatMgr {
    // 当前活跃的心跳管理器实例（用于在无直接引用处更新心跳时间）
    private static volatile HeartbeatMgr CURRENT;
    private static final int HEARTBEAT_INTERVAL = 30;
    private static final int HEARTBEAT_TIMEOUT = HEARTBEAT_INTERVAL * 3;
    private static final long TIMEOUT_GRACE_MS = 3000;

    private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
    private volatile long lastHeartbeatTime = 0;
    private volatile long lastResponseTime = 0;
    private volatile boolean isRunning = false;

    public void startHeartbeat(Channel ch){
        if(isRunning) return;

        isRunning = true;
        lastHeartbeatTime = System.currentTimeMillis();
        lastResponseTime = lastHeartbeatTime;

        // 记录当前活跃实例
        CURRENT = this;

        // 定期发送心跳
        scheduler.scheduleAtFixedRate(() -> {
            if(ch != null && ch.isActive()){
                sendHeartbeat(ch);
            }
        }, HEARTBEAT_INTERVAL, HEARTBEAT_INTERVAL, TimeUnit.SECONDS);

        // 定期检查心跳超时
        scheduler.scheduleAtFixedRate(() -> {
            checkHeartbeatTimeout(ch);
        }, HEARTBEAT_TIMEOUT, HEARTBEAT_TIMEOUT, TimeUnit.SECONDS);

        Log.info("心跳管理器启动，间隔：" + HEARTBEAT_INTERVAL + "秒");
    }
    public void stopHeartbeat(){
        isRunning = false;
        scheduler.shutdown();
        Log.info("心跳管理器已停止");
        // 清理当前实例
        if (CURRENT == this) {
            CURRENT = null;
        }
    }

    private void sendHeartbeat(Channel ch){
        try{
            GamePacket hbpkt = GamePacket.newBuilder()
                .setEc(ErrorCode.SUCCESS)
                .setCmd(CmdId.HEARTBEAT_REQ)
                .build();
            ch.writeAndFlush(hbpkt);
            lastHeartbeatTime = System.currentTimeMillis();
            Log.debug("发送心跳包");
        }
        catch(Exception e){
            Log.err("发送心跳包失败：" + e.getMessage());
        }
    }

    private void checkHeartbeatTimeout(Channel ch){
        long currentTime = System.currentTimeMillis();
        long timeSinceLastResponse = currentTime - lastResponseTime;

        if(timeSinceLastResponse > HEARTBEAT_TIMEOUT * 1000 + TIMEOUT_GRACE_MS){
            Log.err("心跳超时，关闭连接");
            if(ch != null){
                ch.close();
            }
        }
    }

    /**
     * 在任意位置通知：收到心跳响应
     */
    public static void notifyHeartbeatResponse(){
        HeartbeatMgr mgr = CURRENT;
        if(mgr != null){
            mgr.lastResponseTime = System.currentTimeMillis();
        }
    }
}
